<!DOCTYPE html>
<html lang="en">
  <head>
    <title>
        Java-Se-Java8 - rulerLwx Blog
      </title>
        <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui">
    <meta name="renderer" content="webkit">
    <meta http-equiv="Cache-Control" content="no-transform" />
    <meta http-equiv="Cache-Control" content="no-siteapp" />
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="format-detection" content="telephone=no,email=no,adress=no">
    
    <meta name="theme-color" content="#000000" />
    
    <meta http-equiv="window-target" content="_top" />
    
    
    <meta name="description" content="Lambda 表达式（重点） JDK8文档：https://docs.oracle.com/javase/8/docs/ 为什么使用 Lambda Lambda是一个匿名" />
    <meta name="generator" content="Hugo 0.73.0 with theme pure" />
    <title>Java-Se-Java8 - rulerLwx Blog</title>
    
    
    <link rel="stylesheet" href="https://rulerLwx.gitee.io/css/style.min.c4bc7071f132c964c2116bca53b392933f377e5ca7b7051ed245187c621a2d3e.css">
    
    <link rel="stylesheet" href="https://cdn.staticfile.org/highlight.js/9.15.10/styles/github.min.css" async>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.4.2/tocbot.css" async>
    <meta property="og:title" content="Java-Se-Java8" />
<meta property="og:description" content="Lambda 表达式（重点） JDK8文档：https://docs.oracle.com/javase/8/docs/ 为什么使用 Lambda Lambda是一个匿名" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://rulerLwx.gitee.io/2017/07/java-se-java8/" />
<meta property="article:published_time" content="2017-07-01T12:10:47+08:00" />
<meta property="article:modified_time" content="2017-07-01T12:10:47+08:00" />
<meta itemprop="name" content="Java-Se-Java8">
<meta itemprop="description" content="Lambda 表达式（重点） JDK8文档：https://docs.oracle.com/javase/8/docs/ 为什么使用 Lambda Lambda是一个匿名">
<meta itemprop="datePublished" content="2017-07-01T12:10:47&#43;08:00" />
<meta itemprop="dateModified" content="2017-07-01T12:10:47&#43;08:00" />
<meta itemprop="wordCount" content="8132">



<meta itemprop="keywords" content="," /><meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="Java-Se-Java8"/>
<meta name="twitter:description" content="Lambda 表达式（重点） JDK8文档：https://docs.oracle.com/javase/8/docs/ 为什么使用 Lambda Lambda是一个匿名"/>

    <!--[if lte IE 9]>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.1.20170427/classList.min.js"></script>
      <![endif]-->

    <!--[if lt IE 9]>
        <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
      <![endif]-->
  </head>

  
  

  <body class="main-center theme-black" itemscope itemtype="http://schema.org/WebPage"><header class="header" itemscope itemtype="http://schema.org/WPHeader">
    <div class="slimContent">
      <div class="navbar-header">
        <div class="profile-block text-center">
          <a id="avatar" href="https://gitee.com/rulerLwx" target="_blank">
            <img class="img-circle img-rotate" src="https://rulerLwx.gitee.io/avatar.png" width="200" height="200">
          </a>
          <h2 id="name" class="hidden-xs hidden-sm">rulerLwx</h2>
          <h3 id="title" class="hidden-xs hidden-sm hidden-md">thinking...</h3>
          <small id="location" class="text-muted hidden-xs hidden-sm"><i class="icon icon-map-marker"></i>Guangzhou, China</small>
        </div><div class="search" id="search-form-wrap">
    <form class="search-form sidebar-form">
        <div class="input-group">
            <input type="text" class="search-form-input form-control" placeholder="Search" />
            <span class="input-group-btn">
                <button type="submit" class="search-form-submit btn btn-flat" onclick="return false;"><i
                        class="icon icon-search"></i></button>
            </span>
        </div>
        <div class="ins-search">
            <div class="ins-search-mask"></div>
            <div class="ins-search-container">
                <div class="ins-input-wrapper">
                    <input type="text" class="ins-search-input" placeholder="Type something..."
                        x-webkit-speech />
                    <button type="button" class="close ins-close ins-selectable" data-dismiss="modal"
                        aria-label="Close"><span aria-hidden="true">×</span></button>
                </div>
                <div class="ins-section-wrapper">
                    <div class="ins-section-container"></div>
                </div>
            </div>
        </div>
    </form>
</div>
        <button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#main-navbar" aria-controls="main-navbar" aria-expanded="false">
          <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
      </div>
      <nav id="main-navbar" class="collapse navbar-collapse" itemscope itemtype="http://schema.org/SiteNavigationElement" role="navigation">
        <ul class="nav navbar-nav main-nav">
            <li class="menu-item menu-item-home">
                <a href="/">
                    <i class="icon icon-home-fill"></i>
                  <span class="menu-title">Home</span>
                </a>
            </li>
            <li class="menu-item menu-item-archives">
                <a href="/posts/">
                    <i class="icon icon-archives-fill"></i>
                  <span class="menu-title">Archives</span>
                </a>
            </li>
            <li class="menu-item menu-item-categories">
                <a href="/categories/">
                    <i class="icon icon-folder"></i>
                  <span class="menu-title">Categories</span>
                </a>
            </li>
            <li class="menu-item menu-item-tags">
                <a href="/tags/">
                    <i class="icon icon-tags"></i>
                  <span class="menu-title">Tags</span>
                </a>
            </li>
            <li class="menu-item menu-item-about">
                <a href="/about/">
                    <i class="icon icon-cup-fill"></i>
                  <span class="menu-title">About</span>
                </a>
            </li>
        </ul>
      </nav>
    </div>
  </header>

<aside class="sidebar" itemscope itemtype="http://schema.org/WPSideBar">
  <div class="slimContent">
    
      <div class="widget">
    <h3 class="widget-title">Board</h3>
    <div class="widget-body">
        <div id="board">
            <div class="content">enjoy~
            </div>
        </div>
    </div>
</div>

      <div class="widget">
    <h3 class="widget-title"> Categories</h3>
    <div class="widget-body">
        <ul class="category-list">
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-framework/" class="category-list-link">java-framework</a><span class="category-list-count">38</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-front-end/" class="category-list-link">java-front-end</a><span class="category-list-count">11</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-se/" class="category-list-link">java-se</a><span class="category-list-count">21</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-senior/" class="category-list-link">java-senior</a><span class="category-list-count">4</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/linux/" class="category-list-link">linux</a><span class="category-list-count">13</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/tools/" class="category-list-link">tools</a><span class="category-list-count">1</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/%E6%8A%80%E6%9C%AF%E6%9D%82%E7%83%A9/" class="category-list-link">技术杂烩</a><span class="category-list-count">4</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/" class="category-list-link">数据库</a><span class="category-list-count">15</span></li>
        </ul>
    </div>
</div>
      <div class="widget">
    <h3 class="widget-title"> Tags</h3>
    <div class="widget-body">
        <ul class="tag-list">
            
            
            <li class="tag-list-item"><a href="https://rulerLwx.gitee.io/tags/jvm/" class="tag-list-link">jvm</a><span
                    class="tag-list-count">1</span></li>
            
            
            <li class="tag-list-item"><a href="https://rulerLwx.gitee.io/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/" class="tag-list-link">多线程</a><span
                    class="tag-list-count">2</span></li>
            
            
            <li class="tag-list-item"><a href="https://rulerLwx.gitee.io/tags/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/" class="tag-list-link">网络编程</a><span
                    class="tag-list-count">3</span></li>
            
        </ul>

    </div>
</div>
      
<div class="widget">
    <h3 class="widget-title">Recent Posts</h3>
    <div class="widget-body">
        <ul class="recent-post-list list-unstyled no-thumbnail">
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E8%87%AA%E5%B7%B1%E5%8A%A8%E6%89%8B%E4%B8%80%E6%89%B9%E9%87%8F%E7%A7%BB%E5%8A%A8%E9%87%8D%E5%91%BD%E5%90%8D%E6%96%87%E4%BB%B6/" class="title">自己动手（一）——批量移动、重命名文件</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-27 17:50:02 &#43;0800 CST" itemprop="datePublished">2020-07-27</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E5%85%B3%E4%BA%8Einteger%E7%9A%84-128~127%E7%BC%93%E5%AD%98/" class="title">关于Integer的 -128~127缓存</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-11 16:56:21 &#43;0800 CST" itemprop="datePublished">2020-07-11</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E8%B7%A8%E5%9F%9F%E9%97%AE%E9%A2%98/" class="title">跨域问题</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-08 22:41:12 &#43;0800 CST" itemprop="datePublished">2020-07-08</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/" class="title">个人博客搭建</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-05 18:58:47 &#43;0800 CST" itemprop="datePublished">2020-07-05</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/mongodb-1/" class="title">MonggoDB-1</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-03 18:58:47 &#43;0800 CST" itemprop="datePublished">2020-07-03</time>
                    </p>
                </div>
            </li>
        </ul>
    </div>
</div>
  </div>
</aside>

    
    
<aside class="sidebar sidebar-toc collapse" id="collapseToc" itemscope itemtype="http://schema.org/WPSideBar">
  <div class="slimContent">
    <h4 class="toc-title">Catalogue</h4>
    <nav id="toc" class="js-toc toc">

    </nav>
  </div>
</aside>
<main class="main" role="main"><div class="content">
  <article id="-" class="article article-type-" itemscope
    itemtype="http://schema.org/BlogPosting">
    
    <div class="article-header">
      <h1 itemprop="name">
  <a
    class="article-title"
    href="/2017/07/java-se-java8/"
    >Java-Se-Java8</a
  >
</h1>

      <div class="article-meta">
        
<span class="article-date">
  <i class="icon icon-calendar-check"></i>&nbsp;
<a href="https://rulerLwx.gitee.io/2017/07/java-se-java8/" class="article-date">
  <time datetime="2017-07-01 12:10:47 &#43;0800 CST" itemprop="datePublished">2017-07-01</time>
</a>
</span>
<span class="article-category">
  <i class="icon icon-folder"></i>&nbsp;
  <a class="article-category-link" href="/categories/java-se/"> Java-Se </a>
</span>  
  <span class="article-tag">
    <i class="icon icon-tags"></i>&nbsp;
    <a class="article-tag-link" href="/tags//">  </a>
  </span>

        <span class="post-comment"><i class="icon icon-comment"></i>&nbsp;<a href="/2017/07/java-se-java8/#comments"
            class="article-comment-link">Comments</a></span>
		<span class="post-wordcount hidden-xs" itemprop="wordCount">Word Count: 8132words</span>
		<span class="post-readcount hidden-xs" itemprop="timeRequired">Read Count: 17minutes </span>
      </div>
    </div>
    <div class="article-entry marked-body js-toc-content" itemprop="articleBody">
      <h1 id="lambda-表达式重点">Lambda 表达式（重点）</h1>
<p>JDK8文档：https://docs.oracle.com/javase/8/docs/</p>
<h2 id="为什么使用-lambda">为什么使用 Lambda</h2>
<p>Lambda是一个匿名函数，我们可以将 lambda 表达式理解为<strong>一段可以传递的代码</strong>（将代码像数据一样传递）</p>
<pre><code class="language-java">    //原来的匿名内部类
    @Test
    public void test1(){
        Comparator&lt;Integer&gt; comparator = new Comparator&lt;Integer&gt;() {
            @Override
            public int compare(Integer x, Integer y) {
                return Integer.compare(x,y);
            }
        };
        TreeSet&lt;Integer&gt; ts = new TreeSet&lt;&gt;(comparator);
    }

    //使用 Lambda 表达式
    public void test2(){
        Comparator&lt;Integer&gt; comparator = (x, y) -&gt; Integer.compare(x, y);
        TreeSet&lt;Integer&gt; ts = new TreeSet&lt;&gt;(comparator);
    }
</code></pre>
<p>PS：java8-foreach</p>
<pre><code class="language-java">        ArrayList&lt;Object&gt; list = new ArrayList&lt;&gt;();
        list.forEach(System.out::println);
</code></pre>
<h2 id="基础语法">基础语法</h2>
<p>Lambda 表达式由三部分组成：</p>
<ul>
<li>形参列表：0个或多个</li>
<li>箭头：<code>-&gt;</code></li>
<li>代码块：一条语句，或多条语句（用花括号）</li>
</ul>
<p>示例：</p>
<pre><code class="language-java">    public static void main(String[] args) {
        //无参、无返回值
        Runnable r1 = () -&gt; System.out.println(&quot;&quot;);
        r1.run();

        //有一个参数、无返回值
        Consumer&lt;String&gt; consumer = (x) -&gt; System.out.println(x);
        consumer.accept(&quot;这是传给x的参数&quot;);

        //若只有一个参数，括号可以不写
        Consumer&lt;String&gt; consume2 = x -&gt; System.out.println(x);
        consumer.accept(&quot;一个参数&quot;);

        //两个以上参数，有返回值，Lambda 体中有多条语句
        Comparator&lt;Integer&gt; comparator = (x,y) -&gt; {
            System.out.println(&quot;多参、返回值，Lambda体多条语句&quot;);
            return Integer.compare(x,y);
        };
        comparator.compare(1, 2);
    }
</code></pre>
<p>疑问：接口只能有一个抽象方法？</p>
<p>答：并不是所有的接口可以使用<code>Lambda</code>表达式，只<strong>有函数式接口</strong>才能使用<code>Lambda</code>表达式，即，有<code>@FunctionalInterface</code>修饰的接口才能使用<code>Lambda</code>，原则上接口只有一个未实现的方法。 ——20190904</p>
<p>参数列表类型可以不写，因为JVM可以通过上下文推断，判断数据类型</p>
<h2 id="应用示例">应用示例</h2>
<p>1）调用<code>Collections.sort()</code>方法，通过定制排序比较两个<code>Employee</code>（先按年龄，年龄相同再按姓名），使用Lambda作为参数传递。</p>
<pre><code class="language-java">public class MyTest {
    List&lt;Employee&gt; list = Arrays.asList(
            new Employee(101, &quot;张三&quot;, 19, 3333.33),
            new Employee(102, &quot;李四&quot;, 39, 5555.77),
            new Employee(103, &quot;王五&quot;, 29, 9999.88),
            new Employee(104, &quot;李二狗&quot;, 49, 3333.33),
            new Employee(105, &quot;秦二春&quot;, 59, 9999.99)
    );

    @Test
    public void test1(){
        //使用Lambda
        Collections.sort(list,(e1,e2) -&gt; {
            if (e1.getAge() == e2.getAge()) {
                return e1.getName().compareTo(e2.getName());
            }else {
                return Integer.compare(e1.getAge(),e2.getAge());
            }
        });

        //使用匿名内部类
        Collections.sort(list, new Comparator&lt;Employee&gt;() {
            @Override
            public int compare(Employee o1, Employee o2) {
                if (o1.getAge() == o2.getAge()) {
                    return o1.getName().compareTo(o2.getName());
                }else {
                    return Integer.compare(o1.getAge(),o2.getAge());
                }
            }
        });
        
        for (Employee e : list) {
            System.out.println(e);
        }
    }
}
</code></pre>
<h2 id="四大内置函数式接口">四大内置函数式接口</h2>
<table>
<thead>
<tr>
<th>函数式接口</th>
<th>参数类型</th>
<th>返回类型</th>
<th>方法</th>
<th>用途</th>
</tr>
</thead>
<tbody>
<tr>
<td>Consumer<!-- raw HTML omitted -->，消费型接口</td>
<td>T</td>
<td>void</td>
<td><code>void accept(T t);</code></td>
<td>对类型为T的对象应用操作</td>
</tr>
<tr>
<td>Supplier<!-- raw HTML omitted -->，供给型接口</td>
<td></td>
<td>T</td>
<td><code>T get();</code></td>
<td>返回类型为T的对象</td>
</tr>
<tr>
<td>Function&lt;T, R&gt;，函数型接口</td>
<td>T</td>
<td>R</td>
<td><code>R apply(T t);</code></td>
<td>对类型为T的对象应用操作，并返回R类型的对象</td>
</tr>
<tr>
<td>Predicate<!-- raw HTML omitted -->，断定型接口</td>
<td>T</td>
<td>boolean</td>
<td><code>boolean test(T t);</code></td>
<td>确定类型为T的对象是否满足某约束</td>
</tr>
</tbody>
</table>
<p>示例：</p>
<pre><code class="language-java">public class FunctionInterfaceTest {
    /**
     * Consumer&lt;T&gt;，消费型示例
     */
    @Test
    public void test1(){
        happy(10000,(x) -&gt; System.out.println(&quot;花费了：&quot;+x+&quot;元&quot;));
    }

    public void happy(double money, Consumer consumer) {
        consumer.accept(money);
    }

    /**
     * Supplier&lt;T&gt;，供给型示例
     */
    @Test
    public void test2(){
        List&lt;Integer&gt; numList = getNumList(10, () -&gt; (int)(Math.random() * 100));
        for (Integer i : numList) {
            System.out.println(i);
        }
    }

    public List&lt;Integer&gt; getNumList(int num, Supplier&lt;Integer&gt; supplier) {
        ArrayList&lt;Integer&gt; list = new ArrayList&lt;&gt;();
        for (int i = 0; i &lt; num; i++) {
            Integer n = supplier.get();
            list.add(n);
        }
        return list;
    }

    /**
     * Function&lt;T, R&gt;，函数型接口
     */
    @Test
    public void test3(){
        String newStr = strHandler(&quot;ABC&quot;, (str) -&gt; str.trim());
        System.out.println(newStr);
    }

    //处理字符串
    public String strHandler(String str, Function&lt;String,String&gt; fun){
        return fun.apply(str);
    }

    /**
     * Predicate&lt;T&gt;，断定型接口
     */
    @Test
    public void test(){
        List&lt;String&gt; list = Arrays.asList(&quot;abc&quot;, &quot;www.baidu.com&quot;, &quot;www.oschina.com&quot;, &quot;ok&quot;);
        List&lt;String&gt; stringList = filterStr(list, (s -&gt; s.length() &gt; 3));//字符长度大于3
        for (String str : stringList) {
            System.out.println(str);
        }
    }

    public List&lt;String&gt; filterStr(List&lt;String&gt; list, Predicate&lt;String&gt; pre){
        ArrayList&lt;String&gt; strList = new ArrayList&lt;&gt;();
        for (String str : list) {
            if (pre.test(str)) {//判断
                strList.add(str);
            }
        }
        return strList;
    }
}
</code></pre>
<p>总结：核心思想是面向接口编程，可以不管具体实现，用到时再写实现。不会写的时候，就用匿名内部类代替，然后再转为lambda。——20190905</p>
<h1 id="方法引用构造器引用">方法引用、构造器引用</h1>
<p>语法格式：</p>
<table>
<thead>
<tr>
<th>种类</th>
<th>示例</th>
<th>对应的Lambda</th>
</tr>
</thead>
<tbody>
<tr>
<td>引用类方法</td>
<td>类名::类方法</td>
<td>(a,b,..) -&gt; 类名.类方法(a,b,&hellip;)</td>
</tr>
<tr>
<td>引用特定对象的实例方法</td>
<td>对象::实例方法</td>
<td>(a,b,..) -&gt; 对象.实例方法(a,b,&hellip;)</td>
</tr>
<tr>
<td>引用某类对象的实例方法</td>
<td>类名::实例方法</td>
<td>(a,b,..) -&gt; a.实例方法(a,b,&hellip;)</td>
</tr>
<tr>
<td>引用构造器</td>
<td>类名::new</td>
<td>(a,b,..) -&gt; new 类名(a,b,&hellip;)</td>
</tr>
</tbody>
</table>
<p>引用与Lambda之间可以转换！</p>
<p>总结：当 Lambda 只有一行语句时，可以用<code>::</code>的写法，连入参都省了，前提是两者的<strong>形参列表、返回值</strong>相同。</p>
<p>有现成的方法，就引用；没有，就自己用 Lambda 表达式写。</p>
<p>1）引用类方法</p>
<pre><code class="language-java">@FunctionalInterface
interface Converter{
	Integer convert(String from);
}

Converter converter1 = from -&gt; Integer.valueOf(from);

Converter converter1 = Integer::valueOf;
</code></pre>
<p>2）引用特定对象的实例方法</p>
<pre><code class="language-java">Converter converter2 = from -&gt; &quot;fkit.org&quot;.indexOf(from);

Converter converter2 = &quot;fkit.org&quot;::indexOf;

Integer value = converter2.convert(&quot;it&quot;);
</code></pre>
<p>3）引用某类对象的实例方法</p>
<pre><code class="language-java">@FunctionalInterface
interface MyTest
{
	String test(String a , int b , int c);
}

MyTest mt = (a , b , c) -&gt; a.substring(b , c);//第一个参数作为调用者，后面的参数全部传给该方法作为参数。

MyTest mt = String::substring;

String str = mt.test(&quot;Java I Love you&quot; , 2 , 9);
</code></pre>
<p>4）引用构造器</p>
<pre><code class="language-java">@FunctionalInterface
interface YourTest
{
	JFrame win(String title);
}

YourTest yt = (String a) -&gt; new JFrame(a);

YourTest yt = JFrame::new;

JFrame jf = yt.win(&quot;我的窗口&quot;);
System.out.println(jf);
</code></pre>
<p>总结：如何知道调用的是哪个构造函数？<strong>构造函数入参</strong>跟接口中<strong>抽象方法的入参</strong>对应。</p>
<p>5）数组引用</p>
<pre><code class="language-java">@Test
public void test2(){
    Function&lt;Integer, String[]&gt; fun = (x) -&gt; new String[x];
    String[] arr = fun.apply(10);
    System.out.println(arr.length);

    Function&lt;Integer,String[]&gt; fun2 = String[]::new;
    String[] arr2 = fun2.apply(20);
    System.out.println(arr2.length);
}
</code></pre>
<h1 id="接口中的默认方法静态方法">接口中的默认方法、静态方法</h1>
<p>接口中可以定义哪些？</p>
<pre><code>[修饰符] interface 接口名 extends 父接口1,父接口2...
{
    零个到多个常量定义...
    零个到多个抽象方法定义...
    零个到多个内部类、接口、枚举定义...
    零个到多个默认方法或静态方法（类方法）定义...
}
</code></pre>
<p>为什么要有默认方法？</p>
<p>在 java 8 之前，接口与其实现类之间的 耦合度 太高了（tightly coupled），当需要为一个接口添加方法时，所有的实现类都必须随之修改。默认方法解决了这个问题，它可以为接口添加新的方法，而不会破坏已有的接口的实现。这在 lambda 表达式作为 java 8 语言的重要特性而出现之际，为升级旧接口且保持向后兼容（backward compatibility）提供了途径。</p>
<p>参考：https://www.cnblogs.com/sidesky/p/9287710.html</p>
<p>接口默认方法的“类优先”原则：若一个接口中定义了一个默认方法，而另一个父类或接口中又定义了一个同名的方法时</p>
<ul>
<li>选择父类中的方法，如果一个父类提供了具体的实现，那么接口中具有相同名称和参数的默认方法会被忽略</li>
<li>接口冲突，如果父接口提供一个默认方法，而另一个接口也提供一个相同名称和参数列表的方法（不管是否是默认方法），那么必须覆盖该方法来解决冲突</li>
</ul>
<p>总结：</p>
<ul>
<li>接口中定义的变量，如果省略了修改符，则默认是 <code>public static final</code>；</li>
<li>接口中定义的普通方法，不管是否使用<code>public abstract</code>修饰，接口中的普通方法总是使用<code>public abstract</code>来修饰</li>
<li>接口中普通方法不能有实现体，但类方法、默认方法必须要有实现体</li>
</ul>
<p>示例：</p>
<pre><code class="language-java">public interface Output
{
	// 接口里定义的成员变量只能是常量
	int MAX_CACHE_LINE = 50;
	// 接口里定义的普通方法只能是public的抽象方法
	void out();
	void getData(String msg);
	// 在接口中定义默认方法，需要使用default修饰
	default void print(String... msgs)
	{
		for (String msg : msgs)
		{
			System.out.println(msg);
		}
	}
	// 在接口中定义默认方法，需要使用default修饰
	default void test()
	{
		System.out.println(&quot;默认的test()方法&quot;);
	}
	// 在接口中定义类方法，需要使用static修饰
	static String staticTest()
	{
		return &quot;接口里的类方法&quot;;
	}
}
</code></pre>
<p>如何调用接口中的默认方法、类方法？静态方法直接接口名调用，默认方法用<code>InterfaceA.super.foo();</code>或实现类实例调用。</p>
<h1 id="新日期时间-api">新日期、时间 API</h1>
<p>新的API所在包：</p>
<pre><code>java.time //日期、时间
java.time.chrono //年代，日本年号、民国、佛教
java.time.format //格式化
java.time.temporal //日期、时间运算
java.time.zone //时区
</code></pre>
<p>新的API解决了线程安全问题。</p>
<h2 id="传统日期格式化方法">传统日期格式化方法</h2>
<p>原来的<code>SimpleDateFormat</code>存在线程安全问题：</p>
<pre><code class="language-java">    @Test
    public void test1(){
        SimpleDateFormat sdf = new SimpleDateFormat(&quot;yyyyMMdd&quot;);
        Callable&lt;Date&gt; task = new Callable&lt;Date&gt;() {
            @Override
            public Date call() throws Exception {
                return sdf.parse(&quot;20190906&quot;);
            }
        };

        ExecutorService pool = Executors.newFixedThreadPool(1000);

        ArrayList&lt;Future&lt;Date&gt;&gt; result = new ArrayList&lt;&gt;();

        for (int i = 0; i &lt; 10; i++) {
            result.add(pool.submit(task));
        }

        for (Future&lt;Date&gt; future : result) {
            try {
                System.out.println(future.get());
            } catch (Exception e) {
            } 
        }
    }
</code></pre>
<p>可以使用 ThreadLocal 来控制线程安全：</p>
<pre><code class="language-java">public class DateFormatThradLocal {
    private static final ThreadLocal&lt;DateFormat&gt; df = new ThreadLocal&lt;DateFormat&gt;() { //此处是重点
        @Override
        protected DateFormat initialValue() {
            return new SimpleDateFormat(&quot;yyyy-MM-dd&quot;);
        }
    };
    
    public static Date convertToDate(String source) throws ParseException {
        return df.get().parse(source);
    }
    
    public static String convertToString(Date date) throws ParseException {
        return df.get().format(date);
    }
}
</code></pre>
<p>新的日期格式化方法：</p>
<pre><code class="language-java">    /**
     * 使用java8的日期格式化API
     */
    @Test
    public void test3(){
        DateTimeFormatter df = DateTimeFormatter.ofPattern(&quot;yyyy-MM-dd&quot;);
        System.out.println(LocalDate.parse(&quot;2019-09-06&quot;,df));
    }
</code></pre>
<h2 id="api使用示例">API使用示例</h2>
<pre><code class="language-java">    // LocalDate
    // LocalTime 
    // LocalDateTime 它们使用方式相似
    @Test
    public void test1(){
        LocalDateTime dt = LocalDateTime.now();//返回当前时期时间：2019-09-06T22:41:40.890
        System.out.println(dt);

        System.out.println(dt.plusDays(2));//加上两天
        System.out.println(dt.minusDays(2));//减两天，其它类推

        System.out.println(dt.getYear());
        System.out.println(dt.getMonthValue());
        System.out.println(dt.getDayOfMonth());//依次类推...
    }

    // Instant，时间戳（以 Unix 元年，即1970年1月1日零时到某个时间之间的毫秒值）
    @Test
    public void test2(){
        Instant ins = Instant.now();//默认是 UTC 时区
        System.out.println(ins.atOffset(ZoneOffset.ofHours(8)));// UTC + 8 时区（北京时间）
    }

    // Duration，计算两个“时间”之间的间隔
    // Period，计算两个“日期”之间的间隔
    @Test
    public void test3(){
        LocalDateTime ldt1 = LocalDateTime.now();
        //Thread.sleep(1000);//需要try-catch
        LocalDateTime ldt2 = LocalDateTime.now();
        Duration duration = Duration.between(ldt1, ldt2);
        System.out.println(duration);//默认是秒
        System.out.println(duration.toMinutes());//转换成分钟

        LocalDate ld1 = LocalDate.of(2015, 12, 9);
        LocalDate ld2 = LocalDate.now();
        Period period = Period.between(ld1, ld2);
        System.out.println(period);
        System.out.println(period.toTotalMonths());
    }
    
    // TemporalAdjuster，时间校正器
    // TemporalAdjusters，工具类
    @Test
    public void test4(){
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);
        System.out.println(ldt.withDayOfMonth(20));//2019-09-20T10:37:44.230
    }

    // DateTimeFormatter，格式化时间、日期
    @Test
    public void test5(){
        LocalDateTime ldt = LocalDateTime.now();
        DateTimeFormatter df1 = DateTimeFormatter.ISO_DATE;//使用API提供的格式
        DateTimeFormatter df2 = DateTimeFormatter.ofPattern(&quot;yyyy年MM月dd日&quot;);//自定义格式

        System.out.println(ldt.format(df1));
        System.out.println(ldt.format(df2));
    }
    
    // ZonedDateTime
    @Test
    public void test6(){
        Set&lt;String&gt; availableZoneIds = ZoneId.getAvailableZoneIds();// 获取所有的时区ID
        availableZoneIds.forEach(System.out::println);

        ZoneId shanghai = ZoneId.of(&quot;Asia/Shanghai&quot;);
        System.out.println(shanghai.toString());

        LocalDateTime ldt = LocalDateTime.now(ZoneId.of(&quot;Europe/Monaco&quot;));//指定时区创建时间
        System.out.println(ldt);
    }
</code></pre>
<h1 id="stream-api重点">Stream API（重点）</h1>
<p>Stream（流） 是 Java8 中处理集合的关键抽象概念。Stream API 提供了一种高效且易于使用的处理数据的方式。</p>
<p>“集合讲的是数据，流讲的是计算！”。</p>
<p>注意：</p>
<ul>
<li>Stream 自己不会存储数据。</li>
<li>Stream 不会改变源对象。相反，他们会返回一个持有结果的新 Stream；</li>
<li>Stream 操作是延迟的。这意味着他们会等到需要结果时才执行；</li>
</ul>
<p>操作步骤：</p>
<p><img src="https://gitee.com/rulerLwx/PicGo/raw/master/img/20200707202443.png" alt=""></p>
<h2 id="创建流">创建流</h2>
<p>示例：</p>
<pre><code class="language-java">    // 创建 Stream
    @Test
    public void test1(){
        // 方式一：通过 Collection 系列集合提供的 stream() 或 parallelstream()
        ArrayList&lt;String&gt; list = new ArrayList&lt;&gt;();
        Stream&lt;String&gt; stream1 = list.stream();

        // 方式二：通过 Arrays 中的静态方法 stream
        Employee[] empArr = new Employee[10];
        Stream&lt;Employee&gt; stream2 = Arrays.stream(empArr);

        // 方式三：通过 Stream 类中的静态方法 of()
        Stream&lt;String&gt; stream3 = Stream.of(&quot;ab&quot;, &quot;cd&quot;, &quot;ef&quot;);

        // 方式四：创建无限流
        Stream&lt;Integer&gt; stream4 = Stream.iterate(0, (x) -&gt; x + 2);
        stream4.limit(30).forEach(System.out::println);
        Stream.generate(() -&gt; Math.random()).limit(10).forEach(System.out::println);
    }
</code></pre>
<h2 id="中间操作">中间操作</h2>
<p>多个中间操作连接起来就是一个流水线，除非流水线上触发终止操作，否则中间操作不会执行任何的处理，而在终止操作时一次性全部处理，称为“惰性求值”。</p>
<ul>
<li>筛选、切片</li>
<li>映射</li>
<li>排序</li>
</ul>
<p>筛选、切片
方法 | 描述
&mdash;|&mdash;
filter(Predicate&lt;? super T&gt; predicate) | 筛选，接收 Lambda，从流中排除某些元素
distinct() | 筛选，通过流所生成元素的 hashCode() 和 equals() 去除重复元素
limit(long maxSize) | 截断流，使其元素不超过给定数量
skip(long n) | 跳过元素，返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个，则返回一个空流。<!-- raw HTML omitted --> 与 limit(n) 互补。</p>
<p>映射
方法 | 描述
&mdash;|&mdash;
map(Function f) | 接收一个函数作为参数，该函数会被应用到每个元素上，并将其映射成一个新的元素
mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数，该函数会被应用到每个元素上，产生一个新的 DoubleStream
mapToInt(ToIntFunction f) | 接收一个函数作为参数，该函数会被应用到每个元素上，产生一个新的 IntStream
mapToLong(ToLongFunction f) | 接收一个函数作为参数，该函数会被应用到每个元素上，产生一个新的 LongStream
flatMap(Function f) | 接收一个函数作为参数，将流中的每个值都换成另一个流，然后将所有流连接成一个流</p>
<p>总结：map() 和 flatMap() 的区别有点像集合中的 add() addAll()的区别</p>
<p>排序
方法 | 描述
&mdash;|&mdash;
sorted() | 产生一个新流，其中按自然顺序排序（Comparable）
sorted(Comparator comp) | 产生一个新流，其中按比较器顺序排序（Comparator）</p>
<p>示例：</p>
<pre><code class="language-java">    List&lt;Employee&gt; employeeList = Arrays.asList(
            new Employee(101, &quot;张三&quot;, 19, 3333.33),
            new Employee(102, &quot;李四&quot;, 39, 5555.77),
            new Employee(103, &quot;王五&quot;, 29, 9999.88),
            new Employee(104, &quot;李二狗&quot;, 49, 3333.33),
            new Employee(105, &quot;秦二春&quot;, 59, 9999.99)
    );
    // 中间操作
    @Test
    public void test2(){
        Stream&lt;Employee&gt; stream = employeeList.stream().filter(e -&gt; e.getAge() &gt; 20).limit(1);
        stream.forEach(System.out::println);// 终止操作
        
        List&lt;String&gt; stringList = Arrays.asList(&quot;aaa&quot;, &quot;bbb&quot;, &quot;ccc&quot;);
        stringList.stream().map(str -&gt; str.toUpperCase()).forEach(System.out::println);// map
        employeeList.stream().map(Employee::getName).forEach(System.out::println);// 注意Employee::getName写法
        
        stringList.stream().sorted().forEach(System.out::println);// 自然排序
        employeeList.stream().sorted((e1,e2)-&gt;{// 定制排序
            if (e1.getAge().equals(e2.getAge())) {
                return e1.getName().compareTo(e2.getName());
            }else {
                return e1.getAge().compareTo(e2.getAge());
            }
        }).forEach(System.out::println);
    }
</code></pre>
<h2 id="终止操作">终止操作</h2>
<p>终止操作会从流的流水生成结果。其结果可以是任何不是流的值，例如：List、Integet，甚至是 void。</p>
<p>查找与匹配
方法 | 描述
&mdash;|&mdash;
allMatch(Predicate p) | 检查是否匹配所有元素
anyMatch(Predicate p) | 检查是否至少匹配一个元素
noneMatch(Predicate p) | 检查是否没有匹配所有元素
findFirst() | 返回第一个元素
findAny() | 返回当前流中任意元素</p>
<p>归约
方法 | 描述
&mdash;|&mdash;
reduce(T identity, BinaryOperator<!-- raw HTML omitted --> accumulator) | 将流中元素反复结合起来，得到一个值。
reduce(BinaryOperator<!-- raw HTML omitted --> accumulator) |</p>
<p>收集
方法 | 描述
&mdash;|&mdash;
collect(Collector collector) | <code>Collectors</code>工具类提供了很多静态方法来操作集合
collect(Supplier supplier, BiConsumer accumulator,BiConsumer combiner) |</p>
<p>示例：</p>
<pre><code class="language-java">// 终止操作
@Test
public void test3(){
    long count = employeeList.stream().count();
    Optional&lt;Employee&gt; op1 = employeeList.stream()
            .max((e1, e2) -&gt; Double.compare(e1.getSalary(), e2.getSalary()));
    System.out.println(op1.get().getSalary());
    Optional&lt;Double&gt; op2 = employeeList.stream().map(Employee::getSalary).min(Double::compareTo);
    System.out.println(op2.get());
    //归约
    List&lt;Integer&gt; list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    // identity 是起始值，开始时，x=identity=0，然后x作为和，y是list中的下一个元素，相当于是 x += y 操作
    Integer sum = list.stream().reduce(0, (x, y) -&gt; x + y);
    System.out.println(sum);
    Optional&lt;Double&gt; opt3 = employeeList.stream().map(Employee::getSalary).reduce(Double::sum);
    System.out.println(opt3.get());
    //收集
    List&lt;String&gt; list2 = employeeList.stream().map(Employee::getName).collect(Collectors.toList());
    list2.forEach(System.out::println);
    employeeList.stream().map(Employee::getName).collect(Collectors.toSet()).forEach(System.out::print);//set可以去重
    employeeList.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new)).forEach(System.out::print);//收集到 hashset
    Long count1 = employeeList.stream().collect(Collectors.counting());//总数
    Double avg1 = employeeList.stream().collect(Collectors.averagingDouble(Employee::getSalary));//求平均
    System.out.println(avg1);
    Optional&lt;Double&gt; opt4 = employeeList.stream().map(Employee::getSalary).collect(Collectors.maxBy(Double::compare));//最大值
    Optional&lt;Double&gt; opt5 = employeeList.stream().map(Employee::getSalary).collect(Collectors.minBy(Double::compare));//最小值
    System.out.println(opt4.get());
    Map&lt;Integer, List&lt;Employee&gt;&gt; map1 = employeeList.stream().collect(Collectors.groupingBy(Employee::getAge));//分组
    System.out.println(map1);
    Map&lt;String, Map&lt;Integer, List&lt;Employee&gt;&gt;&gt; map2 = employeeList.stream()
            .collect(Collectors.groupingBy(Employee::getName, Collectors.groupingBy(Employee::getAge)));//多级分组，先按姓名，再按年龄
    System.out.println(map2);
    Map&lt;Boolean, List&lt;Employee&gt;&gt; map3 = employeeList.stream()
            .collect(Collectors.partitioningBy((e) -&gt; e.getSalary() &gt; 5000));//分区，按工资大于5000分区
    System.out.println(map3);
    DoubleSummaryStatistics dss = employeeList.stream()
            .collect(Collectors.summarizingDouble(Employee::getSalary));//汇总，跟上面求最大、最小、数量功能相同
    System.out.println(dss.getMax());
    System.out.println(dss.getMin());
    System.out.println(dss.getCount());
    String str1 = employeeList.stream().map(Employee::getName).collect(Collectors.joining(&quot;,&quot;));//连接，名字的拼接
    System.out.println(str1);
}
</code></pre>
<p>map 和 reduce 的连接通常称为 map-reduce 模式，因Google用它来进行网络搜索而出名。</p>
<h2 id="api练习">API练习</h2>
<p>1）给定一个数字列表，如何返回一个由每个数的平方构成的列表？如，给定【1，2，3，4，5】，返回【1，4，9，16，25】</p>
<pre><code class="language-java">    @Test
    public void test4(){
        Integer[] intArr = {1, 2, 3, 4, 5};
        Arrays.stream(intArr).map((x) -&gt; x * x).forEach(System.out::print);
    }
</code></pre>
<p>2）怎样用 map 和 reduce 方法统计流中有多少个 Employee ？</p>
<pre><code class="language-java">    @Test
    public void test5() {
        Optional&lt;Integer&gt; opt1 = employeeList.stream().map(e -&gt; 1).reduce(Integer::sum);//亮点：map(e -&gt; 1)
        System.out.println(opt1.get());
    }
</code></pre>
<p>3）练习题</p>
<pre><code class="language-java">//交易员类
public class Trader {

	private String name;
	private String city;

	public Trader() {
	}

	public Trader(String name, String city) {
		this.name = name;
		this.city = city;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	@Override
	public String toString() {
		return &quot;Trader [name=&quot; + name + &quot;, city=&quot; + city + &quot;]&quot;;
	}
}
</code></pre>
<pre><code class="language-java">//交易类
public class Transaction {

	private Trader trader;
	private int year;
	private int value;

	public Transaction() {
	}

	public Transaction(Trader trader, int year, int value) {
		this.trader = trader;
		this.year = year;
		this.value = value;
	}

	public Trader getTrader() {
		return trader;
	}

	public void setTrader(Trader trader) {
		this.trader = trader;
	}

	public int getYear() {
		return year;
	}

	public void setYear(int year) {
		this.year = year;
	}

	public int getValue() {
		return value;
	}

	public void setValue(int value) {
		this.value = value;
	}

	@Override
	public String toString() {
		return &quot;Transaction [trader=&quot; + trader + &quot;, year=&quot; + year + &quot;, value=&quot;
				+ value + &quot;]&quot;;
	}
}
</code></pre>
<p>练习题：</p>
<pre><code class="language-java">public class TransactionTest {
    List&lt;Transaction&gt; transactions = null;

    @Before
    public void before(){
        Trader raoul = new Trader(&quot;Raoul&quot;, &quot;Cambridge&quot;);
        Trader mario = new Trader(&quot;Mario&quot;, &quot;Milan&quot;);
        Trader alan = new Trader(&quot;Alan&quot;, &quot;Cambridge&quot;);
        Trader brian = new Trader(&quot;Brian&quot;, &quot;Cambridge&quot;);

        transactions = Arrays.asList(
                new Transaction(brian, 2011, 300),
                new Transaction(raoul, 2012, 1000),
                new Transaction(raoul, 2011, 400),
                new Transaction(mario, 2012, 710),
                new Transaction(mario, 2012, 700),
                new Transaction(alan, 2012, 950)
        );
    }
    //1. 找出2011年发生的所有交易， 并按交易额排序（从低到高）
    //2. 交易员都在哪些不同的城市工作过？
    //3. 查找所有来自剑桥的交易员，并按姓名排序
    //4. 返回所有交易员的姓名字符串，按字母顺序排序
    //5. 有没有交易员是在米兰工作的？
    //6. 打印生活在剑桥的交易员的所有交易额
    //7. 所有交易中，最高的交易额是多少
    //8. 找到交易额最小的交易
}
</code></pre>
<p>参考：https://github.com/wangpw2016/java8-day02/blob/master/src/com/atguigu/exer/TestTransaction.java</p>
<pre><code class="language-java">public class TransactionTest {
    List&lt;Transaction&gt; transactions = null;

    @Before
    public void before() {
        Trader raoul = new Trader(&quot;Raoul&quot;, &quot;Cambridge&quot;);
        Trader mario = new Trader(&quot;Mario&quot;, &quot;Milan&quot;);
        Trader alan = new Trader(&quot;Alan&quot;, &quot;Cambridge&quot;);
        Trader brian = new Trader(&quot;Brian&quot;, &quot;Cambridge&quot;);

        transactions = Arrays.asList(
                new Transaction(brian, 2011, 300),
                new Transaction(raoul, 2012, 1000),
                new Transaction(raoul, 2011, 400),
                new Transaction(mario, 2012, 710),
                new Transaction(mario, 2012, 700),
                new Transaction(alan, 2012, 950)
        );
    }

    //1. 找出2011年发生的所有交易， 并按交易额排序（从低到高）
    @Test
    public void test1() {
        transactions.stream()
                .filter(e -&gt; e.getYear() == 2011)
                .sorted((e1, e2) -&gt; Integer.compare(e1.getValue(), e2.getValue()))
                .forEach(System.out::println);
    }

    //2. 交易员都在哪些不同的城市工作过？
    @Test
    public void test2() {
        transactions.stream()
                .map(Transaction::getTrader)
                .map(Trader::getCity)
                .collect(Collectors.toSet())
                .forEach(System.out::println);
    }
    //3. 查找所有来自剑桥的交易员，并按姓名排序
    @Test
    public void test3(){
        transactions.stream()
                .map(Transaction::getTrader)
                .filter(e -&gt; e.getCity().equals(&quot;Cambridge&quot;))
                .sorted((e1,e2) -&gt; e1.getName().compareTo(e2.getName()))
                .distinct()// 去重
                .forEach(System.out::println);
    }
    //4. 返回所有交易员的姓名字符串，按字母顺序排序
    @Test
    public void test4(){
        transactions.stream()
                .map(Transaction::getTrader)
                .map(Trader::getName)
                .sorted()
                .distinct()
                .forEach(System.out::println);
        String str = transactions.stream()
                .map(Transaction::getTrader)
                .map(Trader::getName)
                .sorted().distinct()
                .reduce(&quot;&quot;, String::concat);//重点，归约
        System.out.println(str);
    }

    //5. 有没有交易员是在米兰工作的？
    @Test
    public void test5(){
        boolean b = transactions.stream()
                .anyMatch(e -&gt; &quot;Milan&quot;.equals(e.getTrader().getCity()));
        System.out.println(b);
    }
    //6. 打印生活在剑桥的交易员的所有交易额
    @Test
    public void test6(){
        // 方式一
        IntSummaryStatistics valSum = transactions.stream()
                .filter(t -&gt; &quot;Cambridge&quot;.equals(t.getTrader().getCity()))
                .collect(Collectors.summarizingInt(Transaction::getValue));
        System.out.println(valSum.getSum());
        // 方式二
        Optional&lt;Integer&gt; valSum2 = transactions.stream()
                .filter(t -&gt; &quot;Cambridge&quot;.equals(t.getTrader().getCity()))
                .map(Transaction::getValue)
                .reduce(Integer::sum);
        System.out.println(valSum2.get());
    }
    //7. 所有交易中，最高的交易额是多少
    @Test
    public void test7(){
        // 方式一
        Optional&lt;Transaction&gt; opt = transactions.stream()
                .collect(Collectors.maxBy((e1, e2) -&gt; Integer.compare(e1.getValue(), e2.getValue())));
        System.out.println(opt.get().getValue());
        // 方式二
        Optional&lt;Integer&gt; opt2 = transactions.stream()
                .map(Transaction::getValue)
                .max(Integer::compare);
        System.out.println(opt2.get());
    }
    //8. 找到交易额最小的交易（记录）
    @Test
    public void test8(){
        Optional&lt;Transaction&gt; opt = transactions.stream()
                .min((e1, e2) -&gt; Integer.compare(e1.getValue(), e2.getValue()));
        System.out.println(opt.get());
    }


    //1. 找出2011年发生的所有交易， 并按交易额排序（从低到高）
    //2. 交易员都在哪些不同的城市工作过？
    //3. 查找所有来自剑桥的交易员，并按姓名排序
    //4. 返回所有交易员的姓名字符串，按字母顺序排序
    //5. 有没有交易员是在米兰工作的？
    //6. 打印生活在剑桥的交易员的所有交易额
    //7. 所有交易中，最高的交易额是多少
    //8. 找到交易额最小的交易
}
</code></pre>
<h1 id="optional">Optional</h1>
<p>java.util.Optional 是一个容器类，代表一个值存在或不存在，可以避免空指针异常。</p>
<p>常用方法：</p>
<ul>
<li><code>Optional.of(T t);</code>创建一个 Optional 实例</li>
<li><code>Optional.empty();</code>创建一个空的 Optional 实例</li>
<li><code>Optional.ofNullable(T t);</code>若 T 不为 null ，创建 Optional 实例，否则创建空实例</li>
<li><code>isPresent();</code>判断是否包含值</li>
<li><code>orElse(T t);</code>如果调用对象包含值，返回该值，否则返回 t</li>
<li><code>orElseGet(Supplier&lt;? extends T&gt; s);</code>如果调用对象包含值，返回该值，否则返回 s 获取的值</li>
<li><code>map(Function&lt;? super T, ? extends U&gt; mapper);</code>如果有值，对其处理并返回处理后的 Optional，否则返回<code>Optional.empty();</code></li>
<li><code>flatMap(Function&lt;? super T, Optional&lt;U&gt;&gt; mapper);</code>与 map 类似，要求返回值必须是 Optional</li>
</ul>
<p>使用示例：https://www.cnblogs.com/zhangboyu/p/7580262.html</p>
<h1 id="并行流--顺序流">并行流 &amp; 顺序流</h1>
<p>并行流就是把一个内容分成多个数据块，并用不同的线程分别处理每个数据块的流。</p>
<p>Java8中将并行流进行了优化，Stream API 可以声明性通过 parallel() 与 sequential() 在并行流与顺序流之间切换。</p>
<p>了解 Fork/Join 框架，大任务分为小任务，可以将结果汇总或没有返回值；</p>
<p>java7中关于 Fork/Join 的写法，参考《Java-Se-多线程-1》。</p>
<p>采用“工作窃取”模式（work-stealing）：当执行新的任务时它可以将其拆分成更小的任务执行，并将小任务加到线程队列中，然后再从一个随机的队列中偷一个并把他放在自己的队列中。</p>
<pre><code class="language-java">    // java8
    @Test
    public void test(){
        Instant start = Instant.now();

        LongStream.rangeClosed(0, 100000000000L)
                .parallel()
                .reduce(0, Long::sum);

        Instant end = Instant.now();
        System.out.println(&quot;耗费时间：&quot;+Duration.between(start,end).toMillis()+&quot; 毫秒&quot;);// 34737
    }
</code></pre>
<h1 id="可重复注解类型注解">可重复注解、类型注解</h1>
<p><img src="https://gitee.com/rulerLwx/PicGo/raw/master/img/20200707202602.png" alt=""></p>
<p>解析注解：</p>
<p><img src="https://gitee.com/rulerLwx/PicGo/raw/master/img/20200707202621.png" alt=""></p>

    </div>
    <div class="article-footer">
<blockquote class="mt-2x">
  <ul class="post-copyright list-unstyled">
    <li class="post-copyright-link hidden-xs">
      <strong>Permalink: </strong>
      <a href="https://rulerLwx.gitee.io/2017/07/java-se-java8/" title="Java-Se-Java8" target="_blank" rel="external">https://rulerLwx.gitee.io/2017/07/java-se-java8/</a>
    </li>
    <li class="post-copyright-license">
      <strong>License：</strong><a href="http://creativecommons.org/licenses/by/4.0/deed.zh" target="_blank" rel="external">CC BY 4.0 CN</a>
    </li>
  </ul>
</blockquote>

<div class="panel panel-default panel-badger">
  <div class="panel-body">
    <figure class="media">
      <div class="media-left">
        <a href="https://gitee.com/rulerLwx" target="_blank" class="img-burn thumb-sm visible-lg">
          <img src="https://rulerLwx.gitee.io/avatar.png" class="img-rounded w-full" alt="">
        </a>
      </div>
      <div class="media-body">
        <h3 class="media-heading"><a href="https://gitee.com/rulerLwx" target="_blank"><span class="text-dark">rulerLwx</span><small class="ml-1x">thinking...</small></a></h3>
        <div>Good Good Study, Day Day Up~</div>
      </div>
    </figure>
  </div>
</div>
    </div>
  </article>
<section id="comments">
    <div id="vcomments"></div>
</section>

</div><nav class="bar bar-footer clearfix" data-stick-bottom>
    <div class="bar-inner">
        <ul class="pager pull-left">
            <li class="prev">
                <a href="https://rulerLwx.gitee.io/2017/07/java-senior-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/" title="Java-Senior-设计模式"><i
                        class="icon icon-angle-left"
                        aria-hidden="true"></i><span>&nbsp;&nbsp;Older</span></a>
            </li>
            <li class="next">
                <a href="https://rulerLwx.gitee.io/2017/07/java-se-nio/"
                    title="Java-Se-NIO"><span>Newer&nbsp;&nbsp;</span><i
                        class="icon icon-angle-right" aria-hidden="true"></i></a>
            </li>
            
            <li class="toggle-toc">
                <a class="toggle-btn collapsed" data-toggle="collapse" href="#collapseToc" aria-expanded="false"
                    title="Catalogue" role="button">
                    <span>[&nbsp;</span><span>Catalogue</span>
                    <i class="text-collapsed icon icon-anchor"></i>
                    <i class="text-in icon icon-close"></i>
                    <span>]</span>
                </a>
            </li>
        </ul>
        <div class="bar-right">
            <div class="share-component" data-sites="weibo,qq,wechat"
                data-mobile-sites="weibo,qq,qzone"></div>
        </div>
    </div>
</nav>

</main><footer class="footer" itemscope itemtype="http://schema.org/WPFooter">
<ul class="social-links">
    <li><a href="https://gitee.com/rulerLwx" target="_blank" title="gitee" data-toggle=tooltip data-placement=top >
            <i class="icon icon-gitee"></i></a></li>
    <li><a href="https://github.com/wolf-lea" target="_blank" title="github" data-toggle=tooltip data-placement=top >
            <i class="icon icon-github"></i></a></li>
</ul>
  <div class="copyright">
    &copy;2017  -
    2020
    <div class="publishby">
        Theme by <a href="https://github.com/xiaoheiAh" target="_blank"> xiaoheiAh </a>base on<a href="https://github.com/xiaoheiAh/hugo-theme-pure" target="_blank"> pure</a>.
    </div>
  </div>
</footer>

<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_SVG"></script>
<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
            showMathMenu: false, //disables context menu
            tex2jax: {
            inlineMath: [ ['$','$'], ['\\(','\\)'] ]
           }
    });
</script>


<script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script>
<script>
    window.jQuery || document.write('<script src="js/jquery.min.js"><\/script>')
</script>
<script type="text/javascript" src="https://cdn.staticfile.org/highlight.js/9.15.10/highlight.min.js"></script>
<script type="text/javascript" src="https://cdn.staticfile.org/highlight.js/9.15.10/languages/python.min.js" defer></script>
<script type="text/javascript" src="https://cdn.staticfile.org/highlight.js/9.15.10/languages/javascript.min.js" defer></script><script>
    hljs.configure({
        tabReplace: '    ', 
        classPrefix: ''     
        
    })
    hljs.initHighlightingOnLoad();
</script>
<script src="https://rulerLwx.gitee.io/js/application.min.bdeb64b910570b6c41badc6a05b7afb0c8ad9efd8525de3c7257d59e786326a3.js"></script>
<script src="https://rulerLwx.gitee.io/js/plugin.min.51ff8c7317566f82259170fa36e09c4493adc9b9378b427a01ad3f017ebac7dd.js"></script>

<script>
    (function (window) {
        var INSIGHT_CONFIG = {
            TRANSLATION: {
                POSTS: 'Posts',
                PAGES: 'Pages',
                CATEGORIES: 'Categories',
                TAGS: 'Tags',
                UNTITLED: '(Untitled)',
            },
            ROOT_URL: 'https:\/\/rulerLwx.gitee.io',
            CONTENT_URL: 'https:\/\/rulerLwx.gitee.io\/searchindex.json ',
        };
        window.INSIGHT_CONFIG = INSIGHT_CONFIG;
    })(window);
</script>
<script type="text/javascript" src="https://rulerLwx.gitee.io/js/insight.min.a343cd9a5a7698336b28ef3a7c16a3a1b1d2d5fb17dc8ed04022bbe08cc5459073a15bdafa3a8a58cdd56080784bdd69fa70b1ae8597565c799c57ed00f0e120.js" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.4.2/tocbot.min.js"></script>
<script>
    tocbot.init({
        
        tocSelector: '.js-toc',
        
        contentSelector: '.js-toc-content',
        
        headingSelector: 'h1, h2, h3',
        
        hasInnerContainers: true,
    });
</script>

<script src="https://cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/valine"></script>
<script type="text/javascript">
    var GUEST = ['nick', 'mail', 'link'];
    var meta = 'nick,mail';
    meta = meta.split(',').filter(function (item) {
        return GUEST.indexOf(item) > -1;
    });
    new Valine({
        el: '#vcomments',
        verify: null ,
        notify: null ,
        appId: 'IyAB0PSPRazTPDxitO1ddQ7O-gzGzoHsz',
        appKey: '5rBJTq4KidYF33eXwvRVhtEH',
        placeholder: 'enjoy~',
        avatar: 'mm',
        meta: meta,
        pageSize: '10' || 10,
        visitor: false 
});
</script>

  </body>
</html>
